#ifndef YOOHOO_XMPPIM_XMPPCLIENT_H
#define YOOHOO_XMPPIM_XMPPCLIENT_H

#include "xmppim/export.h"
#include "xmppcore/connectionconfig.h"
#include "xmppcore/tlscallback.h"
#include "xmppcore/connection.h"
#include "xmppcore/presence.h"
#include "xmppcore/message.h"
#include "xmppcore/iq.h"
#include "xmppim/stanzatask.h"
#include "xmppim/stanzalistener.h"
#include "xmppim/errorlistener.h"

#include <QtCore/QObject>

namespace yoohoo_xmppim {

class ConnectionThread;

using namespace yoohoo_xmppcore;

class YOOHOO_XMPPIM_EXPORT XmppClient : QObject {
	Q_OBJECT

public:
	XmppClient(ConnectionConfig& config, TlsCallback* tlsCallback = 0, QObject* parent = 0);
	~XmppClient();
	const ConnectionConfig& config() const;
	void setTlsCallback(TlsCallback* tlsCallback);
	TlsCallback* tlsCallback();
	void connectToHost();
	void disconnectFromHost();
	void authenticate(QString userName, QString password);

	void registerStreamFeature(StreamFeatureFactory* streamFeatureFactory);
	bool isStreamFeatureSupported(QString name, QString namespaceUri);

	void sendIq(Iq iq);
	void sendPresence(Presence presence);
	void sendMessage(Message message);
	void sendXml(const QString& xml);
	void execute(StanzaTask* task);
	void addStanzaListener(StanzaListener* listener);
	void removeStanzaListener(StanzaListener* listener);
	void addStanzaErrorListener(StanzaErrorListener* listener);
	void removeStanzaErrorListener(StanzaErrorListener* listener);
	void setStreamErrorListener(StreamErrorListener* listener);
	void removeStreamErrorListener(StreamErrorListener* listener);

signals:
	void connectionError(yoohoo_xmppcore::Connection::ConnectionError error);
	void connectionState(yoohoo_xmppcore::Connection::ConnectionState state);
	void streamError(yoohoo_xmppcore::StreamError error);
	void stanzaError(yoohoo_xmppcore::StanzaError error);
	void readyToAuthenticate();
	void authenticated();
	void authFailure(yoohoo_xmppcore::Connection::AuthFailure failure);
	void resourceBindingError(yoohoo_xmppcore::Connection::ResourceBindingError error);
	void resourceBinded(QString jid);
	void sessionEstablishmentError(yoohoo_xmppcore::Connection::SessionEstablishmentError error);
	void sessionEstablished();
	void sessionClosed();
	void presenceReceived(yoohoo_xmppcore::Presence presence);
	void messageReceived(yoohoo_xmppcore::Message message);
	void iqReceived(yoohoo_xmppcore::Iq iq);

protected:
	void searchTaskToProcess(Stanza* stanza);

private slots:
	void processConnectionError(Connection::ConnectionError error);
	void processConnectionState(Connection::ConnectionState state);
	void processStreamError(StreamError error);
	void processStanzaError(StanzaError error);
	void processReadyToAuthenticate();
	void processAuthenticated();
	void processAuthFailure(Connection::AuthFailure failure);
	void processResourceBindingError(Connection::ResourceBindingError error);
	void processResourceBinded(QString jid);
	void processSessionEstablishmentError(Connection::SessionEstablishmentError error);
	void processSessionEstablished();
	void processStreamClosed();
	void processMessageReceived(Message message);
	void processPresenceReceived(Presence presence);
	void processIqReceived(Iq iq);

private:
	ConnectionConfig _config;
	TlsCallback* _tlsCallback;
	Connection* _connection;
	JabberId* _from;
	ConnectionThread* _connectionThread;
	QList<StreamFeatureFactory*> _streamFeatureFactories;
	QList<StanzaTask*> _tasks;
	QMutex _tasksLock;
	QList<PresenceListener*> _presenceListeners;
	QList<MessageListener*> _messageListeners;
	QList<IqListener*> _iqListeners;
	QReadWriteLock _presenceListenersLock;
	QReadWriteLock _messageListenersLock;
	QReadWriteLock _iqListenersLock;
	QList<StanzaErrorListener*> _stanzaErrorListeners;
	QMutex _stanzaErrorListenersLock;
	StreamErrorListener* _streamErrorListener;
};

}

#endif
